/*
 * Copyright (c) 2024 endless-sky
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include "ai_talk.h"
#include <memory>
#include <string>
#include <atomic>
#include <thread>
#include <nlohmann/json.hpp>
#include <curl/curl.h>
#include <vector>
#include <functional>
#include <chrono>

// From protocol.h: AudioStreamPacket
struct AudioStreamPacket {
    uint32_t timestamp = 0;
    std::vector<uint8_t> payload;
};

// From protocol.h: BinaryProtocol2 (for WebSocket communication)
struct BinaryProtocol2 {
    uint16_t version;
    uint16_t type;         // Message type (0: OPUS, 1: JSON)
    uint32_t reserved;     // Reserved for future use
    uint32_t timestamp;    // Timestamp in milliseconds
    uint32_t payload_size; // Payload size in bytes
    uint8_t payload[];     // Payload data
} __attribute__((packed));

// From protocol.h: BinaryProtocol3 (for WebSocket communication)
struct BinaryProtocol3 {
    uint8_t type;
    uint8_t reserved;
    uint16_t payload_size;
    uint8_t payload[];
} __attribute__((packed));

// From protocol.h: AbortReason
enum class AbortReason { // Changed to enum class for better scoping
    kNone,
    kWakeWordDetected
};

// From protocol.h: ListeningMode
enum class ListeningMode { // Changed to enum class
    kAutoStop,
    kManualStop,
    kRealtime // 需要 AEC 支持
};

namespace El {
namespace AITalk {

class AITalkImpl : public IAITalk {
public:
    AITalkImpl();
    ~AITalkImpl() override;

    static AITalkImpl &GetInstance();

    bool Start() override;
    void Stop() override;

    bool OpenAudioChannel();
    void CloseAudioChannel();
    bool IsAudioChannelOpened() const;
    bool IsAudioChannelBusy() const;

    void SendAudio(const AudioStreamPacket &packet);
    void SendWakeWordDetected(const std::string &wake_word);
    void SendStartListening(ListeningMode mode);
    void SendStopListening();
    void SendAbortSpeaking(AbortReason reason);
    void SendIotDescriptors(const std::string &descriptors);
    void SendIotStates(const std::string &states);

private:
    void WorkerLoop();
    bool ConnectWebSocket();

    void SendHelloMessage();
    void HandleServerMessage(const char *data, size_t len);
    void SendJsonMessage(const nlohmann::json &jsonMsg);
    void SendBinaryData(const unsigned char *data, size_t len, bool is_audio_opus = false);

    bool IsTimeout() const;
    void ParseServerHello(const nlohmann::json &server_hello_json);

    CURL *ws_curl_handle_ = nullptr;

    std::string accessToken_;
    std::string deviceId_;
    std::string clientId_;
    std::string serverAddress_ = "wss://api.tenclass.net/xiaozhi/v1/";
    int serverPort_ = 8080;
    std::string serverPath_ = "/";
    std::string ota_url_ = "https://api.tenclass.net/xiaozhi/ota/";

    std::atomic<bool> connected_;
    std::atomic<bool> handshakeCompleted_;
    std::atomic<bool> stopRequested_;
    std::thread workerThread_;

    // State variables from Protocol & WebsocketProtocol
    int server_sample_rate_ = 24000;
    int server_frame_duration_ = 60;
    std::string session_id_;
    int protocolVersion_ = 2;
    std::atomic<bool> busy_sending_audio_;
    std::chrono::time_point<std::chrono::steady_clock> last_incoming_time_;
};
} // namespace AITalk
} // namespace El
